home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / ABUSESRC.ZIP / AbuseSrc / macabuse / imlib / image.c < prev    next >
C/C++ Source or Header  |  1997-05-20  |  33KB  |  1,349 lines

  1. #include "emm.hpp"
  2. #include "image.hpp"
  3. #include "macs.hpp"
  4. #include "system.h"
  5. #include "dos.h"
  6. #include "system.h"
  7. #include "exitproc.hpp"
  8. #include "dprint.hpp"
  9.  
  10. #include <math.h>
  11. #ifdef __DOS
  12.   #include <dir.h>
  13. #else
  14.   #include <unistd.h>
  15. #endif
  16. #include <stdlib.h>
  17.  
  18. extern unsigned char current_background;
  19. char *imerr_messages[]={"No error",
  20.                    "Error occured while reading",
  21.             "Incorrect file type",
  22.             "File is corrupted",
  23.              "File not found",
  24.             "Memory allocation trouble",
  25.             "Operation/file type not supported",
  26.             "Error occured while writing, (disk full?)"};
  27.             
  28.                          
  29. short imerror=0;
  30. short swpfile_num=0;
  31.  
  32. short current_error()
  33. { return imerror; }
  34.  
  35. void clear_errors()
  36. {
  37.   if (imerror)
  38.   { dprintf("Program stopped, error : ");
  39.     if (imerror<=imMAX_ERROR)
  40.       dprintf("%s\n",imerr_messages[imerror]);
  41.     else
  42.       dprintf("Unsonsponsered error code, you got trouble\n"); 
  43. #ifdef __DOS_ONLY
  44.     sound(300);
  45.     delay(100);
  46.     nosound();
  47. #else
  48.     dprintf("%c%c\n",7,8);
  49. #endif
  50.     exit(1);
  51.   }
  52. }
  53.  
  54. void set_error(short x)
  55. { imerror=x; }
  56.  
  57. short last_error()
  58. {
  59.   short ec;
  60.   ec=imerror;
  61.   imerror=0;
  62.   return ec;
  63. }
  64.  
  65. linked_list image_list;
  66.  
  67.  
  68. image_descriptor::image_descriptor(short length, short height,
  69.                    int keep_dirties, int static_memory)
  70.  
  71. { clipx1=0; clipy1=0; 
  72.   l=length; h=height; 
  73.   clipx2=l-1; clipy2=h-1; 
  74.   keep_dirt=keep_dirties; 
  75.   static_mem=static_memory;  
  76. }
  77.  
  78. void image::change_size(short new_width, short new_height, unsigned char *page)
  79. {
  80.   delete_page();
  81.   w=new_width;
  82.   h=new_height;
  83.   make_page(new_width,new_height,page);
  84. }
  85.  
  86. image::~image()
  87. {
  88.   image_list.unlink((linked_node *)this);
  89.   delete_page();
  90.   if (special)
  91.     delete special;
  92.  
  93. }
  94.  
  95.  
  96. void make_block(size_t size)
  97. {
  98.   void *dat=jmalloc(size,"make_block : tmp");
  99.   CONDITION(dat,"Memory error : could not make block\n");
  100.   if (dat) jfree((char *)dat);
  101. }
  102.  
  103. unsigned char image::pixel(short x, short y)
  104. {
  105.   CONDITION(x>=0 && x<width() && y>=0 && y<height(),
  106.      "image::pixel Bad pixel xy");
  107.   return (*(scan_line(y)+x));
  108. }
  109.  
  110. void image::putpixel(short x, short y, char color)
  111. {
  112.   CONDITION(x>=0 && x<width() && y>=0 && y<height(),
  113.      "image::putpixel Bad pixel xy");
  114.   if (special)
  115.   { if (x>=special->x1_clip() && x<=special->x2_clip() &&
  116.     y>=special->y1_clip() && y<=special->y2_clip())
  117.       (*(scan_line(y)+x))=color;
  118.   } else (*(scan_line(y)+x))=color;
  119. }
  120.  
  121.  
  122. image::image(short width, short height, unsigned char *page_buffer, short create_descriptor)
  123. {
  124.   w=width;
  125.   h=height;  
  126.   if (create_descriptor || page_buffer)
  127.   { 
  128.     if (create_descriptor==2)
  129.       special=new image_descriptor(width,height,1,(page_buffer!=NULL));
  130.     else special=new image_descriptor(width,height,0,(page_buffer!=NULL));
  131.   } else special=NULL;
  132.   make_page(width,height,page_buffer);
  133.   //  image_list.add_end((linked_node *) this);
  134. }
  135.  
  136. image::image(spec_entry *e, bFILE *fp)
  137. {
  138.   short i; 
  139.   fp->seek(e->offset,0);
  140.   w=fp->read_short();
  141.   h=fp->read_short();
  142.   special=NULL;
  143.   make_page(w,h,NULL);
  144.   for (i=0;i<h;i++)
  145.     fp->read(scan_line(i),w);
  146.   //  image_list.add_end((linked_node *) this); 
  147. }
  148.  
  149. image::image(bFILE *fp)
  150. {
  151.   short i; 
  152.   w=fp->read_short();
  153.   h=fp->read_short();
  154.   special=NULL;
  155.   make_page(w,h,NULL);
  156.   for (i=0;i<h;i++)
  157.     fp->read(scan_line(i),w);
  158.   //  image_list.add_end((linked_node *) this); 
  159. }
  160.  
  161. void image_uninit()
  162. {
  163. /*  image *im;
  164.   while (image_list.first())
  165.   {
  166.     im=(image *)image_list.first();
  167.     image_list.unlink((linked_node *)im);
  168.     delete im;
  169.   } */
  170. }
  171.  
  172.  
  173. void image_cleanup(int ret, void *arg)
  174. { image_uninit(); }
  175.  
  176. void image_init()
  177. {
  178.   unsigned char bt[2];
  179.   unsigned short wrd,*up;
  180.   bt[0]=1;
  181.   bt[1]=0;
  182.   up=(unsigned short *)bt;
  183.   wrd=int_to_intel(*up);
  184.   if (wrd!=0x01)
  185.   { dprintf("Compiled under wrong ENDING-nes, edit system.h and try again\n");
  186.     dprintf("1 (intel) = %d\n",(int)wrd);
  187.     exit(1);
  188.   }
  189.   imerror=0;
  190.   exit_proc(image_cleanup,image_uninit); // important that possible shared memory is deallocated!
  191. }
  192.  
  193.  
  194. long image::total_pixels(unsigned char background)
  195. {
  196.   short i,j;
  197.   long co;
  198.   unsigned char *c;
  199.   for (co=0,i=height()-1;i>=0;i--)
  200.   { c=scan_line(i);
  201.     for (j=width()-1;j>=0;j--,c++)
  202.       if (*c!=background) co++;
  203.   }
  204.   return co;
  205. }
  206.  
  207. void image::clear(short color)
  208. {
  209.   short i;
  210.   if (color==-1) color=current_background;
  211.   if (special)
  212.   { if (special->x1_clip()<=special->x2_clip())
  213.       for (i=special->y2_clip();i>=special->y1_clip();i--)
  214.     memset(scan_line(i)+special->x1_clip(),color,
  215.            special->x2_clip()-special->x1_clip()+1);
  216.   }
  217.   else
  218.     for (i=height()-1;i>=0;i--)
  219.       memset(scan_line(i),color,width());
  220.   add_dirty(0,0,width()-1,height()-1);
  221. }
  222.  
  223.  
  224. image *image::copy()
  225. {
  226.   image *im;
  227.   unsigned char *c,*dat;
  228.   int i;
  229.   dat=(unsigned char *)jmalloc(width(),"image copy");
  230.   im=new image(width(),height());
  231.   for (i=height()-1;i>=0;i--)
  232.   { c=scan_line(i);
  233.     memcpy(dat,c,width());
  234.     c=im->scan_line(i);
  235.     memcpy(c,dat,width());
  236.   }
  237.   jfree((char *)dat);
  238.   return im;
  239. }
  240.  
  241.  
  242.  
  243. void image::line(short x1, short y1,short x2, short y2, unsigned char color)
  244. {
  245.   short i,xc,yc,er,n,m,xi,yi,xcxi,ycyi,xcyi;
  246.   unsigned dcy,dcx;
  247.   // check to make sure that both endpoint are on the screen
  248.  
  249.   short cx1,cy1,cx2,cy2;
  250.  
  251.   // check to see if the line is completly clipped off
  252.   get_clip(cx1,cy1,cx2,cy2);  
  253.   if ((x1<cx1 && x2<cx1) || (x1>cx2 && x2>cx2) || 
  254.       (y1<cy1 && y2<cy1) || (y1>cy2 && y2>cy2))
  255.     return ;
  256.  
  257.   if (x1>x2)        // make sure that x1 is to the left
  258.   {    
  259.     i=x1; x1=x2; x2=i;  // if not swap points
  260.     i=y1; y1=y2; y2=i;
  261.   }  
  262.  
  263.   // clip the left side
  264.   if (x1<cx1)
  265.   {  
  266.     int my=(y2-y1);       
  267.     int mx=(x2-x1),b;
  268.     if (!mx) return ;
  269.     if (my)
  270.     {
  271.       b=y1-(y2-y1)*x1/mx;      
  272.       y1=my*cx1/mx+b;
  273.       x1=cx1;      
  274.     }
  275.     else x1=cx1;
  276.   }
  277.  
  278.   // clip the right side
  279.   if (x2>cx2)
  280.   {  
  281.     int my=(y2-y1);       
  282.     int mx=(x2-x1),b;
  283.     if (!mx) return ;
  284.     if (my)
  285.     {
  286.       b=y1-(y2-y1)*x1/mx;      
  287.       y2=my*cx2/mx+b;
  288.       x2=cx2;      
  289.     }
  290.     else x2=cx2;
  291.   }
  292.  
  293.   if (y1>y2)        // make sure that y1 is on top
  294.   {    
  295.     i=x1; x1=x2; x2=i;  // if not swap points
  296.     i=y1; y1=y2; y2=i;
  297.   }  
  298.  
  299.   // clip the bottom
  300.   if (y2>cy2)
  301.   {  
  302.     int mx=(x2-x1);       
  303.     int my=(y2-y1),b;
  304.     if (!my)
  305.       return ;
  306.     if (mx)
  307.     {
  308.       b=y1-(y2-y1)*x1/mx;      
  309.       x2=(cy2-b)*mx/my;
  310.       y2=cy2;
  311.     }
  312.     else y2=cy2;
  313.   }
  314.  
  315.   // clip the top
  316.   if (y1<cy1)
  317.   {  
  318.     int mx=(x2-x1);       
  319.     int my=(y2-y1),b;
  320.     if (!my) return ;
  321.     if (mx)
  322.     {
  323.       b=y1-(y2-y1)*x1/mx;      
  324.       x1=(cy1-b)*mx/my;
  325.       y1=cy1;
  326.     }
  327.     else y1=cy1;
  328.   }
  329.  
  330.  
  331.   // see if it got cliped into the box, out out
  332.   if (x1<cx1 || x2<cx1 || x1>cx2 || x2>cx2 || y1<cy1 || y2 <cy1 || y1>cy2 || y2>cy2)
  333.     return ;
  334.   
  335.     
  336.  
  337.   if (x1>x2)
  338.   { xc=x2; xi=x1; }
  339.   else { xi=x2; xc=x1; }
  340.  
  341.  
  342.   // assume y1<=y2 from above swap operation
  343.   yi=y2; yc=y1;
  344.  
  345.   add_dirty(xc,yc,xi,yi);
  346.   dcx=x1; dcy=y1;
  347.   xc=(x2-x1); yc=(y2-y1);
  348.   if (xc<0) xi=-1; else xi=1;
  349.   if (yc<0) yi=-1; else yi=1;
  350.   n=abs(xc); m=abs(yc);
  351.   ycyi=abs(2*yc*xi);
  352.   er=0;
  353.  
  354.   if (n>m)
  355.   {
  356.     xcxi=abs(2*xc*xi);
  357.     for (i=0;i<=n;i++)
  358.     {
  359.       *(scan_line(dcy)+dcx)=color;
  360.       if (er>0)
  361.       { dcy+=yi;
  362.     er-=xcxi;
  363.       }
  364.       er+=ycyi;
  365.       dcx+=xi;
  366.     }
  367.   }
  368.   else
  369.   {
  370.     xcyi=abs(2*xc*yi);
  371.     for (i=0;i<=m;i++)
  372.     {
  373.       *(scan_line(dcy)+dcx)=color;
  374.       if (er>0)
  375.       { dcx+=xi;
  376.     er-=ycyi;
  377.       }
  378.       er+=xcyi;
  379.       dcy+=yi;
  380.     }
  381.   }
  382. }
  383.  
  384.  
  385. void image::put_image(image *screen, short x, short y, char transparent)
  386. {
  387.   short i,j,xl,yl;
  388.   unsigned char *pg1,*pg2,*source,*dest;
  389.   if (screen->special)  // the screen is clipped then we onl want to put
  390.             // part of the image
  391.     put_part(screen,x,y,0,0,width()-1,height()-1,transparent);
  392.   else
  393.   {
  394.     if (x<screen->width() && y<screen->height())
  395.     {
  396.       xl=width();
  397.       if (x+xl>screen->width())     // clip to the border of the screen
  398.                 xl=screen->width()-x;
  399.       yl=height();
  400.       if (y+yl>screen->height())
  401.                 yl=screen->height()-y;
  402.  
  403.       int startx=0,starty=0;
  404.       if (x<0) { startx=-x; x=0; }
  405.       if (y<0) { starty=-y; y=0; }
  406.  
  407.       if (xl<0 || yl<0) return ;
  408.  
  409.       screen->add_dirty(x,y,x+xl-1,y+yl-1);
  410.       for (j=starty;j<yl;j++,y++)
  411.       {
  412.                 pg1=screen->scan_line(y);
  413.                 pg2=scan_line(j);
  414.                 if (transparent)
  415.                 {
  416.                   for (i=startx,source=pg2+startx,dest=pg1+x;i<xl;i++,source++,dest++)
  417.                         if (*source!=current_background) *dest=*source;
  418.                 } else memcpy(&pg1[x],pg2,xl);   // strait copy
  419.       }
  420.     }
  421.   }
  422. }
  423.  
  424. void image::fill_image(image *screen, short x1, short y1, short x2, short y2, short allign)
  425. {
  426.   short i,j,w,xx,start,xl,starty;
  427.   unsigned char *pg1,*pg2;
  428.   CHECK(x1<=x2 && y1<=y2);  // we should have gotten this
  429.  
  430.   if (screen->special)
  431.   { x1=screen->special->bound_x1(x1);
  432.     y1=screen->special->bound_y1(y1);
  433.     x2=screen->special->bound_x2(x2);
  434.     y2=screen->special->bound_y2(y2);
  435.   }
  436.   else
  437.   { if (x1<0) x1=0;
  438.     if (y2<0) y1=0;
  439.     if (x2>=screen->width())  x2=screen->width()-1;
  440.     if (y2>=screen->height()) y2=screen->height()-1;
  441.   }
  442.   if (x2<0 || y2<0 || x1>=screen->width() || y1>=screen->height())
  443.     return ;
  444.   screen->add_dirty(x1,y1,x2,y2);
  445.   w=width();
  446.   if (allign)
  447.   {
  448.     start=x1%w;
  449.     starty=y1%height();
  450.   }
  451.   else
  452.   { start=0;
  453.     starty=0;
  454.   }
  455.   for (j=y1;j<=y2;j++)
  456.   {
  457.     pg1=screen->scan_line(j);
  458.     pg2=scan_line(starty++);
  459.     if (starty>=height()) starty=0;
  460.     i=x1;
  461.     xx=start;
  462.     while (i<=x2)
  463.     {
  464.       xl=min(w-xx,x2-i+1);
  465.  
  466.       memcpy(&pg1[i],&pg2[xx],xl);
  467.       xx=0;
  468.       i+=xl;
  469.     }
  470.   }
  471. }
  472.  
  473.  
  474. void image::put_part(image *screen, short x, short y,
  475.         short x1, short y1, short x2, short y2, char transparent)
  476. {
  477.   short xl,yl,j,i;
  478.   short cx1,cy1,cx2,cy2;
  479.   unsigned char *pg1,*pg2,*source,*dest;
  480.   CHECK(x1<=x2 && y1<=y2);
  481.  
  482.   screen->get_clip(cx1,cy1,cx2,cy2);
  483.  
  484.  
  485.   // see if the are to be put is outside of actual image, if so adjust 
  486.   // to fit in the image
  487.   if (x1<0) { x+=-x1; x1=0; }  
  488.   if (y1<0) { y+=-y1; y1=0; }  
  489.   if (x2>=width()) x2=width()-1;
  490.   if (y2>=height()) y2=height()-1;
  491.   if (x1>x2 || y1>y2) return ;      // return if it was adjusted so that nothing will be put
  492.     
  493.  
  494.   // see if the image gets clipped of the screen
  495.   if (x>cx2 || y>cy2 || x+(x2-x1)<cx1 || y+(y2-y1)<cy1) return ;
  496.  
  497.   
  498.   if (x<cx1)
  499.   { x1+=(cx1-x); x=cx1; }
  500.   if (y<cy1)
  501.   { y1+=(cy1-y); y=cy1; }
  502.  
  503.   if (x+x2-x1+1>cx2)
  504.   { x2=cx2-x+x1; }
  505.  
  506.   if (y+y2-y1+1>cy2)
  507.   { y2=cy2-y+y1; }
  508.   if (x1>x2 || y1>y2) return ;    
  509.  
  510.   
  511.  
  512.  
  513.   xl=x2-x1+1;
  514.   yl=y2-y1+1;
  515.  
  516.   screen->add_dirty(x,y,x+xl-1,y+yl-1);
  517.  
  518.   pg1=screen->scan_line(y);
  519.   pg2=scan_line(y1);
  520.  
  521.   if (transparent)
  522.   {
  523.     for (j=0;j<yl;j++)        
  524.     {
  525.       for (i=0,source=&pg2[x1],dest=&pg1[x];i<xl;i++,source++,dest++)    
  526.         if (*source!=current_background) *dest=*source;
  527.       pg1=screen->next_line(y+j,pg1);  
  528.       pg2=next_line(y1+j,pg2);
  529.     }      
  530.   }
  531.   else
  532.   for (j=0;j<yl;j++)
  533.   {    
  534.     memcpy(&pg1[x],&pg2[x1],xl);   // strait copy
  535.     pg1=screen->next_line(y+j,pg1);  
  536.     pg2=next_line(y1+j,pg2);
  537.   }    
  538. }
  539.  
  540. void image::put_part_xrev(image *screen, short x, short y,
  541.         short x1, short y1, short x2, short y2, char transparent)
  542. {
  543.   short xl,yl,j,i;
  544.   short cx1,cy1,cx2,cy2;
  545.   unsigned char *pg1,*pg2,*source,*dest;
  546.   CHECK(x1<=x2 && y1<=y2);
  547.  
  548.   i=x1; x1=width()-x2-1;  // reverse the x locations
  549.   x2=width()-i-1;
  550.  
  551.   if (x1<0)
  552.   { x-=x1; x1=0; }
  553.   if (y1<0)
  554.   { y-=y1; y1=0; }
  555.  
  556.   if (screen->special)
  557.   {
  558.     screen->special->get_clip(cx1,cy1,cx2,cy2);
  559.     if (x>cx2 || y>cy2 || x+(x2-x1)<0 || y+(y2-y1)<0) return ;
  560.     if (x<cx1)
  561.     { x1+=(cx1-x); x=cx1; }
  562.     if (y<cy1)
  563.     { y1+=(cy1-y); y=cy1; }
  564.     if (x+x2-x1+1>cx2)
  565.     { x2=cx2-x+x1; }
  566.     if (y+y2-y1+1>cy2)
  567.     { y2=cy2-y+y1; }
  568.   }
  569.   else  if (x>screen->width() || y>screen->height() || x+x2<0 || y+y2<0)
  570.     return ;
  571.  
  572.   if (x<screen->width() && y<screen->height() && x1<width() && y1<height() &&
  573.       x1<=x2 && y1<=y2)
  574.   {
  575.     if (x2>=width())
  576.       x2=width()-1;
  577.     if (y2>=height())
  578.       y2=height()-1;
  579.     xl=x2-x1+1;
  580.     if (x+xl>screen->width())
  581.       xl=screen->width()-x;
  582.     yl=y2-y1+1;
  583.     if (y+yl>screen->height())
  584.       yl=screen->height()-y;
  585.     screen->add_dirty(x,y,x+xl-1,y+yl-1);
  586.     for (j=0;j<yl;j++)
  587.     {
  588.       pg1=screen->scan_line(y+j);
  589.       pg2=scan_line(y1+j);
  590.       if (transparent)
  591.       {
  592.                 for (i=0,source=&pg2[x1],dest=&pg1[x+xl-1];i<xl;i++,source++,dest--)
  593.           if (*source!=current_background) *dest=*source;
  594.       }
  595.       else 
  596.                 for (i=0,source=&pg2[x1],dest=&pg1[x+xl-1];i<xl;i++,source++,dest++)
  597.           *dest=*source;
  598.     }
  599.   }
  600. }
  601.  
  602.  
  603. void image::put_part_masked(image *screen, image *mask, short x, short y,
  604.         short maskx, short masky,
  605.         short x1, short y1, short x2, short y2)
  606. {
  607.   short xl,yl,j,i,ml,mh;
  608.   short cx1,cy1,cx2,cy2;
  609.   unsigned char *pg1,*pg2,*pg3;
  610.   CHECK(x1<=x2 && y1<=y2);
  611.  
  612.   if (screen->special)
  613.   {
  614.     screen->special->get_clip(cx1,cy1,cx2,cy2);
  615.     if (x>cx2 || y>cy2 || x+(x2-x1)<0 || y+(y2-y1)<0) return ;
  616.     if (x<cx1)
  617.     { x1+=(cx1-x); x=cx1; }
  618.     if (y<cy1)
  619.     { y1+=(cy1-y); y=cy1; }
  620.     if (x+x2-x1>cx2)
  621.     { x2=cx2+x1-x; }
  622.     if (y+y2-y1>cy2)
  623.     { y2=cy2+y1-y; }
  624.   }
  625.   else  if (x>screen->width() || y>screen->height() || x+x1<0 || y+y1<0)
  626.     return ;
  627.  
  628.   ml=mask->width();
  629.   mh=mask->height();
  630.   if (x<screen->width() && y<screen->height() && x1<width() && y1<height() &&
  631.       maskx<ml && masky<mh && x1<=x2 && y1<=y2)
  632.   {
  633.  
  634.     if (x2>=width())
  635.       x2=width()-1;
  636.     if (y2>=height())
  637.       y2=height()-1;
  638.     xl=x2-x1+1;
  639.     if (x+xl>screen->width())
  640.       xl=screen->width()-x-1;
  641.     yl=y2-y1+1;
  642.     if (y+yl>screen->height())
  643.       yl=screen->height()-y-1;
  644.     screen->add_dirty(x,y,x+xl-1,y+yl-1);
  645.     for (j=0;j<yl;j++)
  646.     {
  647.       pg1=screen->scan_line(y+j);
  648.       pg2=scan_line(y1+j);
  649.       pg3=mask->scan_line(masky++);
  650.       if (masky>=mh)           // wrap the mask around if out of bounds
  651.                 masky=0;
  652.       for (i=0;i<xl;i++)
  653.       {
  654.                 if (pg3[maskx+i])          // check to make sure not 0 before putting
  655.                   pg1[x+i]=pg2[x1+i];
  656.                 if (maskx>=ml)            // wrap x around if it goes to far
  657.                   maskx=0;
  658.       }
  659.     }
  660.   }
  661. }
  662.  
  663.  
  664.  
  665. unsigned char image::brightest_color(palette *pal)
  666. { unsigned char *p,r,g,b,bri;
  667.   short i,j;
  668.   long brv;
  669.   brv=0; bri=0;
  670.   for (j=0;j<h;j++)
  671.   {
  672.     p=scan_line(j);
  673.     for (i=0;i<w;i++)
  674.     { pal->get(p[i],r,g,b);
  675.       if ((long)r*(long)g*(long)b>brv)
  676.       { brv=(long)r*(long)g*(long)b;
  677.     bri=p[i];
  678.       }
  679.     }
  680.   }
  681.   return bri;
  682. }
  683.  
  684. unsigned char image::darkest_color(palette *pal, short noblack)
  685. { unsigned char *p,r,g,b,bri;
  686.   short i,j;
  687.   long brv,x;
  688.   brv=(long)258*(long)258*(long)258; bri=0;
  689.   for (j=0;j<h;j++)
  690.   {
  691.     p=scan_line(j);
  692.     for (i=0;i<w;i++)
  693.     { pal->get(p[i],r,g,b);
  694.       x=(long)r*(long)g*(long)b;
  695.       if (x<brv && (x || !noblack))
  696.       { brv=x;
  697.     bri=p[i];
  698.       }
  699.     }
  700.   }
  701.   return bri;
  702. }
  703.  
  704. void image::rectangle(short x1, short y1,short x2, short y2, unsigned char color)
  705. {
  706.   line(x1,y1,x2,y1,color);
  707.   line(x2,y1,x2,y2,color);
  708.   line(x1,y2,x2,y2,color);
  709.   line(x1,y1,x1,y2,color);
  710. }
  711.  
  712. void image::set_clip(short x1, short y1, short x2, short y2)
  713. {
  714.   // If the image does not already have an Image descriptor, allocate one.
  715.  
  716.   if (!special)
  717.   { 
  718.     // create a new image descriptor withj no dirty rectangle keeping
  719.     special=new image_descriptor(width(),height(),0);
  720.   }
  721.   special->set_clip(x1,y1,x2,y2);  // set the image descriptor what the clip
  722.                // should be it will adjust to fit wiothin the image.
  723. }
  724.  
  725. void image::get_clip (short &x1, short &y1, short &x2, short &y2)
  726. {
  727.   if (special)
  728.     special->get_clip(x1,y1,x2,y2);
  729.   else
  730.   { x1=0; y1=0; x2=width()-1; y2=height()-1; }
  731. }
  732.  
  733. void image::in_clip  (short x1, short y1, short x2, short y2)
  734. {
  735.   if (special)
  736.   {
  737.     if (x1<special->x1_clip())
  738.       x1=special->x1_clip();
  739.     if (y1<special->y1_clip())
  740.       y1=special->y1_clip();
  741.     if (x2>special->x2_clip())
  742.       x2=special->x2_clip();
  743.     if (y2>special->y2_clip())
  744.       y2=special->y2_clip();
  745.   }
  746.   set_clip(x1,y1,x2,y2);
  747. }
  748. // this function reduces the number of dirty rectanges
  749. // to 1 by find the minmum area that can contain all the rectangles and
  750. // making this the new dirty area
  751. void image_descriptor::reduce_dirties()
  752. {
  753.   dirty_rect *p,*q;
  754.   short x1,y1,x2,y2,nn;
  755.   x1=6000; y1=6000;
  756.   x2=0; y2=0;
  757.   p=(dirty_rect *)dirties.first();
  758.   nn=dirties.number_nodes();
  759.   while (nn>0)
  760.   {
  761.     if (p->dx1<x1) x1=p->dx1;
  762.     if (p->dy1<y1) y1=p->dy1;
  763.     if (p->dx2>x2) x2=p->dx2;
  764.     if (p->dy2>y2) y2=p->dy2;
  765.     q=p;
  766.     p=(dirty_rect *)p->next();
  767.     dirties.unlink((linked_node *)q);
  768.     delete q;
  769.     nn--;
  770.   }
  771.   dirties.add_front((linked_node *) new dirty_rect(x1,y1,x2,y2));
  772. }
  773.  
  774. void image_descriptor::delete_dirty(int x1, int y1, int x2, int y2)
  775. {
  776.   short i,ax1,ay1,ax2,ay2;
  777.   dirty_rect *p,*next;
  778.   if (keep_dirt)
  779.   {
  780.     if (x1<0) x1=0;
  781.     if (y1<0) y1=0;
  782.     if (x2>=(int)l) x2=l-1;
  783.     if (y2>=(int)h) y2=h-1;
  784.     if (x1>x2) return;
  785.     if (y1>y2) return ;
  786.  
  787.     i=dirties.number_nodes();
  788.     if (!i)
  789.       return ;
  790.     else
  791.     {
  792.       for (p=(dirty_rect *)dirties.first();i;i--,p=(dirty_rect *)next)
  793.       {
  794.         next=(dirty_rect *)p->next();
  795.         // are the two touching?
  796.     if (!(x2<p->dx1 || y2<p->dy1 || x1>p->dx2 || y1>p->dy2))
  797.         {
  798.           // does it take a x slice off? (across)
  799.           if (x2>=p->dx2 && x1<=p->dx1)
  800.           {
  801.             if (y2>=p->dy2 && y1<=p->dy1)
  802.             {
  803.               dirties.unlink((linked_node *)p);
  804.               delete p;
  805.             } 
  806.             else if (y2>=p->dy2)
  807.               p->dy2=y1-1;
  808.             else if (y1<=p->dy1)
  809.               p->dy1=y2+1;
  810.             else
  811.             {
  812.               dirties.add_front((linked_node *) new dirty_rect(p->dx1,p->dy1,p->dx2,y1-1));
  813.               p->dy1=y2+1;
  814.             }
  815.           } 
  816.           // does it take a y slice off (down)
  817.           else if (y2>=p->dy2 && y1<=p->dy1)
  818.           {
  819.             if (x2>=p->dx2)
  820.               p->dx2=x1-1;
  821.             else if (x1<=p->dx1)
  822.               p->dx1=x2+1;
  823.             else 
  824.             {
  825.               dirties.add_front((linked_node *) new dirty_rect(p->dx1,p->dy1,x1-1,p->dy2));
  826.               p->dx1=x2+1;
  827.             }
  828.           }
  829.           // otherwise it just takes a little chunk off
  830.           else 
  831.           {
  832.             if (x2>=p->dx2)      { ax1=p->dx1; ax2=x1-1; }
  833.             else if (x1<=p->dx1) { ax1=x2+1; ax2=p->dx2; }
  834.             else                { ax1=p->dx1; ax2=x1-1; } 
  835.             if (y2>=p->dy2)      { ay1=y1; ay2=p->dy2; }
  836.             else if (y1<=p->dy1) { ay1=p->dy1; ay2=y2; }
  837.             else                { ay1=y1; ay2=y2; }
  838.             dirties.add_front((linked_node *) new dirty_rect(ax1,ay1,ax2,ay2));
  839.           
  840.             if (x2>=p->dx2 || x1<=p->dx1)  { ax1=p->dx1; ax2=p->dx2; }
  841.             else                         { ax1=x2+1; ax2=p->dx2; } 
  842.  
  843.             if (y2>=p->dy2)
  844.             { if (ax1==p->dx1) { ay1=p->dy1; ay2=y1-1; }
  845.                           else { ay1=y1; ay2=p->dy2;   } }
  846.             else if (y1<=p->dy1) { if (ax1==p->dx1) { ay1=y2+1; ay2=p->dy2; }
  847.                                              else  { ay1=p->dy1; ay2=y2; } }
  848.             else           { if (ax1==p->dx1) { ay1=p->dy1; ay2=y1-1; }
  849.                              else { ay1=y1; ay2=y2; } }
  850.             dirties.add_front((linked_node *) new dirty_rect(ax1,ay1,ax2,ay2));
  851.  
  852.             if (x1>p->dx1 && x2<p->dx2)
  853.             {
  854.               if (y1>p->dy1 && y2<p->dy2)
  855.               {
  856.                 dirties.add_front((linked_node *) new dirty_rect(p->dx1,p->dy1,p->dx2,y1-1));
  857.                 dirties.add_front((linked_node *) new dirty_rect(p->dx1,y2+1,p->dx2,p->dy2));
  858.               } else if (y1<=p->dy1)
  859.                 dirties.add_front((linked_node *) new dirty_rect(p->dx1,y2+1,p->dx2,p->dy2));
  860.               else 
  861.                 dirties.add_front((linked_node *) new dirty_rect(p->dx1,p->dy1,p->dx2,y1-1));
  862.             } else if (y1>p->dy1 && y2<p->dy2)
  863.               dirties.add_front((linked_node *) new dirty_rect(p->dx1,y2+1,p->dx2,p->dy2));
  864.             dirties.unlink((linked_node *) p);
  865.             delete p;
  866.           }
  867.         }
  868.       }
  869.     }
  870.   }
  871. }
  872.  
  873. // specifies that an area is a dirty
  874. void image_descriptor::add_dirty(int x1, int y1, int x2, int y2)
  875. {
  876.   short i;
  877.   dirty_rect *p;
  878.   if (keep_dirt)
  879.   {
  880.     if (x1<0) x1=0;
  881.     if (y1<0) y1=0;
  882.     if (x2>=(int)l) x2=l-1;
  883.     if (y2>=(int)h) y2=h-1;
  884.     if (x1>x2) return;
  885.     if (y1>y2) return ;
  886.     
  887.     i=dirties.number_nodes();
  888.     if (!i)
  889.       dirties.add_front((linked_node *) new dirty_rect(x1,y1,x2,y2));
  890.     else if (i>=MAX_DIRTY)
  891.     {
  892.       dirties.add_front((linked_node *) new dirty_rect(x1,y1,x2,y2));
  893.       reduce_dirties();  // reduce to one dirty rectangle, we have to many
  894.     }
  895.     else
  896.     {  
  897.       for (p=(dirty_rect *)dirties.first();i>0;i--)
  898.       {
  899.  
  900.         // check to see if this new rectangle completly encloses the check rectangle
  901.                 if (x1<=p->dx1 && y1<=p->dy1 && x2>=p->dx2 && y2>=p->dy2)
  902.                 {
  903.                   dirty_rect *tmp=(dirty_rect*) p->next();
  904.                   dirties.unlink((linked_node *)p);
  905.                   delete p;
  906.                   if (!dirties.first())
  907.                       i=0;
  908.                   else p=tmp;      
  909.                 }    
  910.                 else if (!(x2<p->dx1 || y2<p->dy1 || x1>p->dx2 || y1>p->dy2))
  911.                 {      
  912.             
  913.             
  914.                  
  915.             /*          if (x1<=p->dx1) { a+=p->dx1-x1; ax1=x1; } else ax1=p->dx1;
  916.                       if (y1<=p->dy1) { a+=p->dy1-y1; ay1=y1; } else ay1=p->dy1; 
  917.                       if (x2>=p->dx2) { a+=x2-p->dx2; ax2=x2; } else ax2=p->dx2;
  918.                       if (y2>=p->dy2) { a+=y2-p->dy2; ay2=y2; } else ay2=p->dy2;
  919.                   
  920.                   if (a<50) 
  921.                   { p->dx1=ax1;                         // then expand the dirty
  922.                     p->dy1=ay1;
  923.                     p->dx2=ax2;
  924.                     p->dy2=ay2;
  925.                     return ;
  926.                   } 
  927.                   else */
  928.                     {
  929.                       if (x1<p->dx1)
  930.                         add_dirty(x1,max(y1,p->dy1),p->dx1-1,min(y2,p->dy2));
  931.                       if (x2>p->dx2)
  932.                         add_dirty(p->dx2+1,max(y1,p->dy1),x2,min(y2,p->dy2));
  933.                       if (y1<p->dy1)
  934.                         add_dirty(x1,y1,x2,p->dy1-1);
  935.                       if (y2>p->dy2)
  936.                         add_dirty(x1,p->dy2+1,x2,y2);
  937.                       return ;
  938.                     }
  939.                     p=(dirty_rect *)p->next();
  940.                   } else p=(dirty_rect *)p->next();      
  941.     
  942.       } 
  943.       CHECK(x1<=x2 && y1<=y2);
  944.       dirties.add_end((linked_node *)new dirty_rect(x1,y1,x2,y2)); 
  945.     }
  946.   }
  947. }
  948.  
  949. void image::bar      (short x1, short y1, short x2, short y2, unsigned char color)
  950. {
  951.   short y;
  952.   if (x1>x2 || y1>y2) return ;
  953.   if (special)
  954.   { x1=special->bound_x1(x1);
  955.     y1=special->bound_y1(y1);
  956.     x2=special->bound_x2(x2);
  957.     y2=special->bound_y2(y2);
  958.   }
  959.   else
  960.   { if (x1<0) x1=0;
  961.     if (y1<0) y1=0;
  962.     if (x2>=width())  x2=width()-1;
  963.     if (y2>=height()) y2=height()-1;
  964.   }
  965.   if (x2<0 || y2<0 || x1>=width() || y1>=height() || x2<x1 || y2<y1)
  966.     return ;
  967.   for (y=y1;y<=y2;y++)
  968.     memset(scan_line(y)+x1,color,(x2-x1+1));
  969.   add_dirty(x1,y1,x2,y2);
  970. }
  971.  
  972. void image::xor_bar  (short x1, short y1, short x2, short y2, unsigned char color)
  973. {
  974.   short y,x;
  975.   if (x1>x2 || y1>y2) return ;
  976.   if (special)
  977.   { x1=special->bound_x1(x1);
  978.     y1=special->bound_y1(y1);
  979.     x2=special->bound_x2(x2);
  980.     y2=special->bound_y2(y2);
  981.   }
  982.   else
  983.   { if (x1<0) x1=0;
  984.     if (y1<0) y1=0;
  985.     if (x2>=width())  x2=width()-1;
  986.     if (y2>=height()) y2=height()-1;
  987.   }
  988.   if (x2<0 || y2<0 || x1>=width() || y1>=height() || x2<x1 || y2<y1)
  989.     return ;
  990.  
  991.   unsigned char *sl=scan_line(y1)+x1; 
  992.   for (y=y1;y<=y2;y++)
  993.   {
  994.     unsigned char *s=sl;
  995.     for (x=x1;x<=x2;x++,s++)
  996.       *s=(*s)^color;
  997.     sl+=w;
  998.   }
  999.  
  1000.   add_dirty(x1,y1,x2,y2);
  1001. }
  1002.  
  1003.  
  1004. void image::unpack_scanline(short line, char bitsperpixel)
  1005. {
  1006.   short x;
  1007.   unsigned char *sl,*ex,mask,bt,sh;
  1008.   ex=(unsigned char *)jmalloc(width(),"image::unpacked scanline");
  1009.   sl=scan_line(line);
  1010.   memcpy(ex,sl,width());
  1011.  
  1012.   if (bitsperpixel==1)      { mask=128;           bt=8; }
  1013.   else if (bitsperpixel==2) { mask=128+64;        bt=4; }
  1014.   else                 {  mask=128+64+32+16; bt=2; }
  1015.  
  1016.   for (x=0;x<width();x++)
  1017.   { sh=((x%bt)<<(bitsperpixel-1));
  1018.     sl[x]=(ex[x/bt]&(mask>>sh))>>(bt-sh-1);
  1019.   }
  1020.  
  1021.   jfree((char *)ex);
  1022. }
  1023.  
  1024. void image::dither(palette *pal)
  1025. {
  1026.   short x,y,i,j;
  1027.   unsigned char dt_matrix[]={0,  136,24, 170,
  1028.            68, 204,102,238,
  1029.            51, 187, 17,153,
  1030.            119,255, 85,221};
  1031.  
  1032.   unsigned char *sl;
  1033.   for (y=height()-1;y>=0;y--)
  1034.   {
  1035.     sl=scan_line(y);
  1036.     for (i=0,j=y%4,x=width()-1;x>=0;x--)
  1037.     {
  1038.       if (pal->red(sl[x])>dt_matrix[j*4+i])
  1039.     sl[x]=255;
  1040.       else sl[x]=0;
  1041.       if (i==3) i=0; else i++;
  1042.     }
  1043.   }
  1044. }
  1045.  
  1046. void image_descriptor::clear_dirties()
  1047. {
  1048.   dirty_rect *dr;
  1049.   dr=(dirty_rect *)dirties.first();  
  1050.   while (dr)
  1051.   { dirties.unlink(dr);
  1052.     delete dr;
  1053.     dr=(dirty_rect *)dirties.first();
  1054.   }
  1055. }
  1056.  
  1057. void image::resize(short new_width, short new_height)
  1058. {
  1059.   int old_width=width(),old_height=height();
  1060.   unsigned char *im=(unsigned char *)jmalloc(width()*height(),"image::resized");
  1061.   memcpy(im,scan_line(0),width()*height());
  1062.  
  1063.   delete_page();
  1064.   make_page(new_width,new_height,NULL);
  1065.   w=new_width;      // set the new hieght and width
  1066.   h=new_height;
  1067.  
  1068.   unsigned char *sl1,*sl2;
  1069.   short y,y2,x2;
  1070.   double yc,xc,yd,xd;
  1071.  
  1072.  
  1073.  
  1074.   yc=(double)old_height/(double)new_height;
  1075.   xc=(double)old_width/(double)new_width;
  1076.   for (y2=0,yd=0;y2<new_height;yd+=yc,y2++)
  1077.   {
  1078.     y=(int)yd;
  1079.     sl1=im+y*old_width;
  1080.     sl2=scan_line(y2);
  1081.     for (xd=0,x2=0;x2<new_width;xd+=xc,x2++)
  1082.     { sl2[x2]=sl1[(int)xd]; }
  1083.   }
  1084.   jfree(im);
  1085.   if (special) special->resize(new_width,new_height);
  1086. }
  1087.  
  1088. void image::scroll(short x1, short y1, short x2, short y2, short xd, short yd)
  1089. {
  1090.   short cx1,cy1,cx2,cy2;
  1091.   CHECK(x1>=0 && y1>=0 && x1<x2 && y1<y2 && x2<width() && y2<height());
  1092.   if (special)
  1093.   {
  1094.     special->get_clip(cx1,cy1,cx2,cy2);
  1095.     x1=max(x1,cx1); y1=max(cy1,y1); x2=min(x2,cx2); y2=min(y2,cy2);
  1096.   }
  1097.   short xsrc,ysrc,xdst,ydst,xtot=x2-x1-abs(xd)+1,ytot,xt;
  1098.   unsigned char *src,*dst;
  1099.   if (xd<0) { xsrc=x1-xd; xdst=x1; } else { xsrc=x2-xd; xdst=x2; }
  1100.   if (yd<0) { ysrc=y1-yd; ydst=y1; } else { ysrc=y2-yd; ydst=y2; }
  1101.   for (ytot=y2-y1-abs(yd)+1;ytot;ytot--)
  1102.   { src=scan_line(ysrc)+xsrc;
  1103.     dst=scan_line(ydst)+xdst;
  1104.     if (xd<0)
  1105.       for (xt=xtot;xt;xt--)
  1106.         *(dst++)=*(src++);
  1107.       else for (xt=xtot;xt;xt--)
  1108.         *(dst--)=*(src--);
  1109.     if (yd<0) { ysrc++; ydst++; } else { ysrc--; ydst--; }
  1110.   }
  1111.   add_dirty(x1,y1,x2,y2);
  1112. }
  1113.  
  1114.  
  1115. image *image::create_smooth(short smoothness)
  1116. {
  1117.   short i,j,k,l,t,d;
  1118.   image *im;
  1119.   CHECK(smoothness>=0);
  1120.   if (!smoothness) return NULL;
  1121.   d=smoothness*2+1;
  1122.   d=d*d;
  1123.   im=new image(width(),height());
  1124.   for (i=0;i<width();i++)
  1125.     for (j=0;j<height();j++)
  1126.     {
  1127.       for (t=0,k=-smoothness;k<=smoothness;k++)
  1128.     for (l=-smoothness;l<=smoothness;l++)
  1129.       if (i+k>smoothness && i+k<width()-smoothness && j+l<height()-smoothness && j+l>smoothness)
  1130.         t+=pixel(i+k,j+l);
  1131.       else t+=pixel(i,j);
  1132.       im->putpixel(i,j,t/d);
  1133.     }
  1134.   return im;
  1135. }
  1136.  
  1137. void image::wiget_bar(short x1, short y1, short x2, short y2, 
  1138.        unsigned char light, unsigned char med, unsigned char dark)
  1139. {
  1140.   line(x1,y1,x2,y1,light);
  1141.   line(x1,y1,x1,y2,light);
  1142.   line(x2,y1+1,x2,y2,dark);
  1143.   line(x1+1,y2,x2-1,y2,dark);
  1144.   bar(x1+1,y1+1,x2-1,y2-1,med);
  1145. }
  1146.  
  1147. class fill_rec
  1148. {
  1149. public :
  1150.   short x,y;
  1151.   fill_rec *last;
  1152.   fill_rec(short X, short Y, fill_rec *Last)
  1153.   { x=X; y=Y; last=Last; }
  1154. } ;
  1155.  
  1156. void image::flood_fill(short x, short y, unsigned char color)
  1157. {
  1158.   unsigned char *sl,*above,*below;
  1159.   fill_rec *recs=NULL,*r;
  1160.   unsigned char fcolor;
  1161.   sl=scan_line(y);
  1162.   fcolor=sl[x];
  1163.   if (fcolor==color) return ;
  1164.   do
  1165.   {
  1166.     if (recs)
  1167.     { r=recs;
  1168.       recs=recs->last;
  1169.       x=r->x; y=r->y;
  1170.       delete r;
  1171.     }
  1172.     sl=scan_line(y);
  1173.     if (sl[x]==fcolor)
  1174.     {
  1175.       while (sl[x]==fcolor && x>0) x--;
  1176.       if (sl[x]!=fcolor) x++;
  1177.       if (y>0)
  1178.       {
  1179.         above=scan_line(y-1);
  1180.         if (above[x]==fcolor)
  1181.         { r=new fill_rec(x,y-1,recs);
  1182.           recs=r;  
  1183.         }
  1184.       }
  1185.       if (y<height()-1)
  1186.       {
  1187.         above=scan_line(y+1);
  1188.         if (above[x]==fcolor)
  1189.         { r=new fill_rec(x,y+1,recs);
  1190.           recs=r;
  1191.         }
  1192.       }
  1193.  
  1194.  
  1195.  
  1196.       do
  1197.       {
  1198.         sl[x]=color; 
  1199.         if (y>0)
  1200.         { above=scan_line(y-1);
  1201.           if (x>0 && above[x-1]!=fcolor && above[x]==fcolor)
  1202.           { r=new fill_rec(x,y-1,recs);
  1203.             recs=r;  
  1204.           }
  1205.         }
  1206.         if (y<height()-1)
  1207.         { below=scan_line(y+1);
  1208.           if (x>0 && below[x-1]!=fcolor && below[x]==fcolor)
  1209.           { r=new fill_rec(x,y+1,recs);
  1210.             recs=r;  
  1211.           }
  1212.         }
  1213.         x++;
  1214.       } while (sl[x]==fcolor && x<width());
  1215.       x--;
  1216.       if (y>0)
  1217.       {
  1218.         above=scan_line(y-1);
  1219.         if (above[x]==fcolor)
  1220.         { r=new fill_rec(x,y-1,recs);
  1221.           recs=r;
  1222.         }
  1223.       }
  1224.       if (y<height()-1)
  1225.       {
  1226.         above=scan_line(y+1);
  1227.         if (above[x]==fcolor)
  1228.         { r=new fill_rec(x,y+1,recs);
  1229.           recs=r;
  1230.         }
  1231.       }
  1232.     }
  1233.   } while (recs);
  1234. }
  1235.  
  1236.  
  1237. #define LED_L 5
  1238. #define LED_H 5
  1239. void image::burn_led(short x, short y, long num, short color, short scale)
  1240. {
  1241.   char st[100];
  1242.   short ledx[]={1,2,1,2,3,3,3,3,1,2,0,0,0,0};
  1243.   short ledy[]={3,3,0,0,1,2,4,6,7,7,4,6,1,2};
  1244.  
  1245.   short dig[]={2+4+8+16+32+64,4+8,2+4+1+32+16,2+4+1+8+16,64+1+4+8,
  1246.              2+64+1+8+16,64+32+1+8+16,2+4+8,1+2+4+8+16+32+64,64+2+4+1+8,1};
  1247.   short xx,yy,zz;
  1248.   sprintf(st,"%8ld",num);
  1249.   for (xx=0;xx<8;xx++)
  1250.   {
  1251.     if (st[xx]!=' ')
  1252.     {
  1253.       if (st[xx]=='-')
  1254.     zz=10;
  1255.       else
  1256.     zz=st[xx]-'0';
  1257.       for (yy=0;yy<7;yy++)
  1258.     if ((1<<yy)&dig[zz])
  1259.       line(x+ledx[yy*2]*scale,y+ledy[yy*2]*scale,x+ledx[yy*2+1]*scale,
  1260.         y+ledy[yy*2+1]*scale,color);
  1261.     }
  1262.     x+=6*scale;
  1263.   }
  1264. }
  1265.  
  1266. unsigned char dither_matrix[]={0,  136,24, 170,
  1267.              68, 204,102,238,
  1268.              51, 187, 17,153,
  1269.              119,255, 85,221};
  1270.  
  1271. image *image::copy_part_dithered (short x1, short y1, short x2, short y2)
  1272. {
  1273.   short x,y,cx1,cy1,cx2,cy2,ry,rx,bo,dity,ditx;
  1274.   image *ret;
  1275.   unsigned char *sl1,*sl2;
  1276.   get_clip(cx1,cy1,cx2,cy2);
  1277.   if (y1<cy1) y1=cy1;
  1278.   if (x1<cx1) x1=cx1;
  1279.   if (y2>cy2) y2=cy2;
  1280.   if (x2>cx2) x2=cx2;
  1281.   CHECK(x2>=x1 && y2>=y1);
  1282.   if (x2<x1 || y2<y1) return NULL;
  1283.   ret=new image((x2-x1+8)/8,(y2-y1+1));
  1284.   if (!last_loaded())
  1285.     ret->clear();
  1286.   else 
  1287.     for (y=y1,ry=0,dity=(y1%4)*4;y<=y2;y++,ry++)
  1288.     {
  1289.       sl1=ret->scan_line(ry);     // sl1 is the scan linefo the return image
  1290.       sl2=scan_line(y);          // sl2 is the orginal image scan line
  1291.       memset(sl1,0,(x2-x1+8)/8);
  1292.       for (bo=7,rx=0,x=x1,ditx=x1%4;x<=x2;x++)
  1293.       {
  1294.         if (last_loaded()->red(sl2[x])>dither_matrix[ditx+dity]) 
  1295.           sl1[rx]|=1<<bo;
  1296.         if (bo!=0)
  1297.       bo--;
  1298.         else
  1299.         {
  1300.         rx++;
  1301.       bo=7;
  1302.         }
  1303.         ditx+=1; if (ditx>3) ditx=0;
  1304.       }
  1305.       dity+=4; if (dity>12) dity=0;
  1306.     }
  1307.   return ret;
  1308. }
  1309.  
  1310. void image::flip_x()
  1311. {
  1312.   unsigned char *rev=(unsigned char *)jmalloc(width(),"image tmp::flipped_x"),*sl;
  1313.   CONDITION(rev,"memory allocation"); 
  1314.   int y,x,i;
  1315.   for (y=0;y<height();y++)
  1316.   { sl=scan_line(y);
  1317.     for (i=0,x=width()-1;x>=0;x--,i++)
  1318.       rev[i]=sl[x]; 
  1319.     memcpy(sl,rev,width());
  1320.   }
  1321.   jfree(rev);
  1322. }
  1323.  
  1324. void image::flip_y()
  1325. {
  1326.   unsigned char *rev=(unsigned char *)jmalloc(width(),"image::flipped_y"),*sl;
  1327.   CONDITION(rev,"memory allocation"); 
  1328.   int y;
  1329.   for (y=0;y<height()/2;y++)
  1330.   { sl=scan_line(y);
  1331.     memcpy(rev,sl,width());
  1332.     memcpy(sl,scan_line(height()-y-1),width());
  1333.     memcpy(scan_line(height()-y-1),rev,width());
  1334.   }
  1335. }
  1336.  
  1337. void image::make_color(unsigned char color)
  1338. {
  1339.   unsigned char *sl;
  1340.   int y,x;
  1341.   for (y=0;y<height();y++)
  1342.   {
  1343.     sl=scan_line(y);
  1344.     for (x=width();x;x--,sl++)
  1345.       if (*sl) 
  1346.         *sl=color;
  1347.   }
  1348. }
  1349.